package com.seed.bpmn.provider.camunda.common.util;

import com.seed.bpmn.engine.common.constants.BpmnConstants;
import com.seed.bpmn.engine.common.util.Empty;
import com.seed.bpmn.engine.dto.FlowDTO;
import com.seed.bpmn.engine.dto.NodeDTO;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.camunda.bpm.engine.RuntimeService;
import org.camunda.bpm.engine.TaskService;
import org.camunda.bpm.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.camunda.bpm.engine.impl.pvm.PvmActivity;
import org.camunda.bpm.engine.impl.pvm.PvmScope;
import org.camunda.bpm.engine.impl.pvm.PvmTransition;
import org.camunda.bpm.engine.impl.pvm.process.ActivityImpl;
import org.camunda.bpm.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * Camunda流程工具类
 *
 * @author cscz89@126.com
 */
@Service
public class CamundaUtil extends BpmnConstants {

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    /**
     * 获取多执行实例执行数量
     * @param taskId 任务id
     * @return
     */
    public Map<String,Integer> getMultiInstVars(String taskId){
        Map<String, Integer> nrVariables = new HashMap<String, Integer>();

        if(Empty.isNotEmpty(taskId)){
            //多实例要用到的变量名
            List<String> nrVariableNames = new ArrayList<String>();
            //多实例总数量
            nrVariableNames.add(ATTRIBUTE_MULTIINSTANCE_TOTAL);
            //多实例已完成数量
            nrVariableNames.add(ATTRIBUTE_MULTIINSTANCE_COMPLETED);

            Task task = this.taskService.createTaskQuery().taskId(taskId).singleResult();
            if(Empty.isNotEmpty(task)) {
                Map<String, Object> nrVars = runtimeService.getVariables(task.getExecutionId(), nrVariableNames);

                Object nrTotal = nrVars.get(ATTRIBUTE_MULTIINSTANCE_TOTAL);
                Object nrCompleted = nrVars.get(ATTRIBUTE_MULTIINSTANCE_COMPLETED);

                if(Empty.isNotEmpty(nrTotal) && Empty.isNotEmpty(nrCompleted)){
                    nrVariables.put(ATTRIBUTE_MULTIINSTANCE_TOTAL,(Integer) nrTotal);
                    nrVariables.put(ATTRIBUTE_MULTIINSTANCE_COMPLETED,(Integer) nrCompleted);
                }
            }
        }
        return nrVariables;
    }

    /**
     * 判断当前任务是不是多实例环节中最后一个，true:是、false不是
     * @param taskId 任务id
     * @return
     */
    public boolean multiInstLast(String taskId){
        Map<String, Integer> nrVariables = this.getMultiInstVars(taskId);

        Integer nrTotal = nrVariables.get(ATTRIBUTE_MULTIINSTANCE_TOTAL);
        Integer nrCompleted = nrVariables.get(ATTRIBUTE_MULTIINSTANCE_COMPLETED);

        if(Empty.isNotEmpty(nrTotal) && Empty.isNotEmpty(nrCompleted)){
            //当前任务为多实例任务中的最后一个实例，
            return nrCompleted + 1 == nrTotal ;
        }else{
            return false;
        }
    }

    /**
     * 递归获取下一节点数据
     * @param taskId 任务id
     * @param transitions 当前任务出去的流转线集合
     * @param flows 下一流转线及目标任务节点配置集合
     * @param flow 需保留的上一个流转线
     */
    public void getNextTransitionsProperties(String taskId, List<PvmTransition> transitions, List<FlowDTO> flows, FlowDTO flow){
        for(PvmTransition t : transitions){
            FlowDTO dto = new FlowDTO();

            //流转线目标，有：网关、任务节点、子流程、结束事件等
            PvmActivity d = t.getDestination();

            //流转线目标类型
            String type = (String)d.getProperty(ATTRIBUTE_TYPE);

            if("noneEndEvent".equals(type)){
                type = "endEvent";
            }else if("multiInstanceBody".equals(type)){
                type = "multiInstance";
                String nodeId = d.getId().replace("#multiInstanceBody","");

                ProcessDefinitionEntity pde = (ProcessDefinitionEntity)d.getFlowScope();
                d = pde.findActivity(nodeId);

                type = (String)d.getProperty(ATTRIBUTE_TYPE);
            }

            //流转线ID
            String id = t.getId();

            //流转线名称
            String name = t.getProperty(ATTRIBUTE_NAME) + "";

            if(Empty.isNotEmpty(flow)){
                id = flow.getId();
                name = flow.getName();
            }
            flow = null;

            //封装流转线上的参数
            String fd = (String) t.getProperty(ELEMENT_DOCUMENTATION);
            if(Empty.isNotEmpty(fd)){
                JSONObject fed = JSONObject.fromObject(fd);
                if(fed.has(BpmnConstants.ATTRIBUTE_FLOW_BACK)){
                    dto.setBack(fed.getBoolean(BpmnConstants.ATTRIBUTE_FLOW_BACK));
                }

                if(fed.has(BpmnConstants.ATTRIBUTE_CONTROL_CODE)){
                    JSONArray controlCode = fed.getJSONArray(BpmnConstants.ATTRIBUTE_CONTROL_CODE);
                    dto.setControlCode(DTOUtil.arrayToMap(controlCode));
                }
            }

            if(type.endsWith(ELEMENT_GATEWAY) || ELEMENT_TASK_SERVICE.equals(type)){
                //目标类型为网关或者serviceTask时，继续获取
                List<PvmTransition> tsList = d.getOutgoingTransitions();
                this.getNextTransitionsProperties(taskId, tsList, flows,flow);
            }else if(ELEMENT_SUBPROCESS.equals(type)){

                dto.setId(id);
                dto.setName(name);
                dto.setType(type);

                ActivityImpl a = (ActivityImpl)d.getProperty("initial");

                List<PvmTransition> outgoingTransitions = a.getOutgoingTransitions();
                if(!Empty.isEmpty(outgoingTransitions)){
                    //获取开始节点后的第一个用户任务的属性
                    PvmActivity destination = outgoingTransitions.get(0).getDestination();

                    String seds = (String) destination.getProperty(ELEMENT_DOCUMENTATION);
                    JSONObject sed = new JSONObject();
                    if(Empty.isNotEmpty(seds)){
                        sed = JSONObject.fromObject(seds);
                    }

                    //流程节点信息封装
                    NodeDTO n = new NodeDTO();
                    n.setId(destination.getId());
                    n.setName(destination.getProperty(ATTRIBUTE_NAME).toString());
                    //流程节点配置封装
                    n = DTOUtil.getNodeDTO(sed,n);

                    dto.setNode(n);
                }

                flows.add(dto);

            }else if(ELEMENT_EVENT_END.equals(type)){
                //-----目标类型为结束事件时----

                //获取结束事件父亲对象
                PvmScope parent = d.getFlowScope();

                //父亲对象为非流程定义对象时
                if(parent instanceof PvmActivity){
                    String parentType = (String)parent.getProperty(ATTRIBUTE_TYPE);

                    //子流程中的结束节点
                    if(ELEMENT_SUBPROCESS.equals(parentType)) {
                        //多实例属性
                        String multiInstance = (String) parent.getProperty(ATTRIBUTE_TASK_MULTIINSTANCE);

                        if(Empty.isNotEmpty(multiInstance)){
                            //判断当前任务是不是多实例环节中最后一个
                            boolean islast = this.multiInstLast(taskId);

                            //不是最后一个实例时，封装当前流转线
                            if(!islast){
                                flow = new FlowDTO();
                                flow.setId(id);
                                flow.setName(name);
                            }

                            //使用子流程对象，继续获取子流程目标对象相关配置信息
                            PvmActivity parentActivity = (PvmActivity) parent;
                            List<PvmTransition> tsList = parentActivity.getOutgoingTransitions();
                            this.getNextTransitionsProperties(taskId, tsList, flows,flow);
                        }
                    }else{
                        //非子流程
                        PvmActivity parentActivity = (PvmActivity) parent;
                        List<PvmTransition> tsList = parentActivity.getOutgoingTransitions();
                        this.getNextTransitionsProperties(taskId, tsList, flows,flow);
                    }
                }else if(parent instanceof ProcessDefinitionEntity){
                    dto.setId(id);
                    dto.setName(name);
                    dto.setType(type);

                    NodeDTO n = new NodeDTO();
                    n.setId(d.getId());

                    dto.setNode(n);
                    flows.add(dto);
                }
            }else{

                dto.setId(id);
                dto.setName(name);
                dto.setType(type);

                String nodeType = null;

                //获取流程节点documentation上配置的参数
                String dd = (String) d.getProperty(ELEMENT_DOCUMENTATION);
                JSONObject documentation = new JSONObject();
                if(Empty.isNotEmpty(dd)){
                    documentation = JSONObject.fromObject(dd);
                    //获取下一节点类型
                    if(documentation.has(ATTRIBUTE_TYPE)){
                        nodeType = documentation.getString(ATTRIBUTE_TYPE);
                    }
                }

                //下一节点为拟稿节点
                if(ATTRIBUTE_TASK_DRAFT.equals(nodeType)){
                    List<PvmTransition> tsList = d.getOutgoingTransitions();
                    this.getNextTransitionsProperties(taskId, tsList, flows,flow);
                    continue;
                }else{
                    NodeDTO n = new NodeDTO();
                    n.setId(d.getId());
                    n.setGroups(documentation.get(ATTRIBUTE_TASK_USER_CANDIDATEGROUPS)+"");

                    //传阅任务节点时,添加节点名称
                    if(ATTRIBUTE_TASK_CIRCULATION.equals(nodeType)){
                        n.setName(d.getProperty(ATTRIBUTE_NAME).toString());
                    }
                    //流程节点配置封装
                    n = DTOUtil.getNodeDTO(documentation,n);
                    dto.setNode(n);
                }

                flows.add(dto);
            }
        }
    }
}
